/*
* insn_fetch - fetch the next 1 to 4 bytes from instruction stream
- *
* @_type: u8, u16, u32, s8, s16, or s32
* @_size: 1, 2, or 4 bytes
- * @_eip: address to fetch from guest memory
- * @_length: increments the current instruction length counter by _size
- *
- * This is used internally by hvm_instruction_length to fetch the next byte,
- * word, or dword from guest memory at location _eip. we currently use a local
- * unsigned long as the storage buffer since the most bytes we're gonna get
- * is limited to 4.
*/
-#define insn_fetch(_type, _size, _eip, _length) \
-({ unsigned long _x; \
- if ((rc = inst_copy_from_guest((unsigned char *)(&(_x)), \
- (unsigned long)(_eip), _size)) \
- != _size) \
- goto done; \
- (_eip) += (_size); \
- (_length) += (_size); \
- (_type)_x; \
+#define insn_fetch(_type, _size) \
+({ unsigned long _x, _ptr = _regs.eip; \
+ if ( mode == X86EMUL_MODE_REAL ) _ptr += _regs.cs << 4; \
+ rc = inst_copy_from_guest((unsigned char *)(&(_x)), _ptr, _size); \
+ if ( rc != _size ) goto done; \
+ _regs.eip += (_size); \
+ length += (_size); \
+ (_type)_x; \
})
/**
{
uint8_t b, d, twobyte = 0, rex_prefix = 0;
uint8_t modrm, modrm_mod = 0, modrm_reg = 0, modrm_rm = 0;
- unsigned int op_bytes, ad_bytes, lock_prefix = 0, rep_prefix = 0, i;
+ unsigned int op_bytes, ad_bytes, i;
int rc = 0;
int length = 0;
unsigned int tmp;
/* Shadow copy of register state. Committed on successful emulation. */
struct cpu_user_regs _regs = *regs;
- /* include CS for 16-bit modes */
- if (mode == X86EMUL_MODE_REAL || mode == X86EMUL_MODE_PROT16)
- _regs.eip += (_regs.cs << 4);
-
switch ( mode )
{
case X86EMUL_MODE_REAL:
/* Legacy prefixes. */
for ( i = 0; i < 8; i++ )
{
- switch ( b = insn_fetch(uint8_t, 1, _regs.eip, length) )
+ switch ( b = insn_fetch(uint8_t, 1) )
{
case 0x66: /* operand-size override */
op_bytes ^= 6; /* switch between 2/4 bytes */
case 0x64: /* FS override */
case 0x65: /* GS override */
case 0x36: /* SS override */
- break;
case 0xf0: /* LOCK */
- lock_prefix = 1;
- break;
case 0xf3: /* REP/REPE/REPZ */
- rep_prefix = 1;
- break;
case 0xf2: /* REPNE/REPNZ */
break;
default:
}
done_prefixes:
- /* Note quite the same as 80386 real mode, but hopefully good enough. */
- if ( (mode == X86EMUL_MODE_REAL) && (ad_bytes != 2) ) {
- printf("sonofabitch!! we don't support 32-bit addresses in realmode\n");
- goto cannot_emulate;
- }
-
/* REX prefix. */
if ( (mode == X86EMUL_MODE_PROT64) && ((b & 0xf0) == 0x40) )
{
op_bytes = 8; /* REX.W */
modrm_reg = (b & 4) << 1; /* REX.R */
/* REX.B and REX.X do not need to be decoded. */
- b = insn_fetch(uint8_t, 1, _regs.eip, length);
+ b = insn_fetch(uint8_t, 1);
}
/* Opcode byte(s). */
if ( b == 0x0f )
{
twobyte = 1;
- b = insn_fetch(uint8_t, 1, _regs.eip, length);
+ b = insn_fetch(uint8_t, 1);
d = twobyte_table[b];
}
/* ModRM and SIB bytes. */
if ( d & ModRM )
{
- modrm = insn_fetch(uint8_t, 1, _regs.eip, length);
+ modrm = insn_fetch(uint8_t, 1);
modrm_mod |= (modrm & 0xc0) >> 6;
modrm_reg |= (modrm & 0x38) >> 3;
modrm_rm |= (modrm & 0x07);
{
case 0:
if ( (modrm_rm == 4) &&
- (((insn_fetch(uint8_t, 1, _regs.eip, length)) & 7)
+ (((insn_fetch(uint8_t, 1)) & 7)
== 5) )
{
length += 4;
case 1:
if ( modrm_rm == 4 )
{
- insn_fetch(uint8_t, 1, _regs.eip, length);
+ insn_fetch(uint8_t, 1);
}
length += 1;
_regs.eip += 1; /* skip disp8 */
case 2:
if ( modrm_rm == 4 )
{
- insn_fetch(uint8_t, 1, _regs.eip, length);
+ insn_fetch(uint8_t, 1);
}
length += 4;
_regs.eip += 4; /* skip disp32 */
/* NB. Immediates are sign-extended as necessary. */
switch ( tmp )
{
- case 1: insn_fetch(int8_t, 1, _regs.eip, length); break;
- case 2: insn_fetch(int16_t, 2, _regs.eip, length); break;
- case 4: insn_fetch(int32_t, 4, _regs.eip, length); break;
+ case 1: insn_fetch(int8_t, 1); break;
+ case 2: insn_fetch(int16_t, 2); break;
+ case 4: insn_fetch(int32_t, 4); break;
}
break;
case SrcImmByte:
- insn_fetch(int8_t, 1, _regs.eip, length);
+ insn_fetch(int8_t, 1);
break;
}
if ( tmp == 8 ) tmp = 4;
switch ( tmp )
{
- case 1: insn_fetch(int8_t, 1, _regs.eip, length); break;
- case 2: insn_fetch(int16_t, 2, _regs.eip, length); break;
- case 4: insn_fetch(int32_t, 4, _regs.eip, length); break;
+ case 1: insn_fetch(int8_t, 1); break;
+ case 2: insn_fetch(int16_t, 2); break;
+ case 4: insn_fetch(int32_t, 4); break;
}
goto done;
}
#endif /* __i386__ */
/* Fetch next part of the instruction being emulated. */
-#define insn_fetch(_type, _size, _eip) \
-({ unsigned long _x; \
- rc = ops->read_std((unsigned long)(_eip), &_x, (_size), ctxt); \
+#define insn_fetch(_type, _size) \
+({ unsigned long _x, _ptr = _regs.eip; \
+ if ( mode == X86EMUL_MODE_REAL ) _ptr += _regs.cs << 4; \
+ rc = ops->read_std(_ptr, &_x, (_size), ctxt); \
if ( rc != 0 ) \
goto done; \
- (_eip) += (_size); \
+ _regs.eip += (_size); \
(_type)_x; \
})
/* Legacy prefixes. */
for ( i = 0; i < 8; i++ )
{
- switch ( b = insn_fetch(uint8_t, 1, _regs.eip) )
+ switch ( b = insn_fetch(uint8_t, 1) )
{
case 0x66: /* operand-size override */
op_bytes ^= 6; /* switch between 2/4 bytes */
op_bytes = 8; /* REX.W */
modrm_reg = (b & 4) << 1; /* REX.R */
/* REX.B and REX.X do not need to be decoded. */
- b = insn_fetch(uint8_t, 1, _regs.eip);
+ b = insn_fetch(uint8_t, 1);
}
/* Opcode byte(s). */
if ( b == 0x0f )
{
twobyte = 1;
- b = insn_fetch(uint8_t, 1, _regs.eip);
+ b = insn_fetch(uint8_t, 1);
d = twobyte_table[b];
}
/* ModRM and SIB bytes. */
if ( d & ModRM )
{
- modrm = insn_fetch(uint8_t, 1, _regs.eip);
+ modrm = insn_fetch(uint8_t, 1);
modrm_mod |= (modrm & 0xc0) >> 6;
modrm_reg |= (modrm & 0x38) >> 3;
modrm_rm |= (modrm & 0x07);
{
case 0:
if ( (modrm_rm == 4) &&
- (((sib = insn_fetch(uint8_t, 1, _regs.eip)) & 7) == 5) )
+ (((sib = insn_fetch(uint8_t, 1)) & 7) == 5) )
_regs.eip += 4; /* skip disp32 specified by SIB.base */
else if ( modrm_rm == 5 )
_regs.eip += 4; /* skip disp32 */
break;
case 1:
if ( modrm_rm == 4 )
- sib = insn_fetch(uint8_t, 1, _regs.eip);
+ sib = insn_fetch(uint8_t, 1);
_regs.eip += 1; /* skip disp8 */
break;
case 2:
if ( modrm_rm == 4 )
- sib = insn_fetch(uint8_t, 1, _regs.eip);
+ sib = insn_fetch(uint8_t, 1);
_regs.eip += 4; /* skip disp32 */
break;
}
/* NB. Immediates are sign-extended as necessary. */
switch ( src.bytes )
{
- case 1: src.val = insn_fetch(int8_t, 1, _regs.eip); break;
- case 2: src.val = insn_fetch(int16_t, 2, _regs.eip); break;
- case 4: src.val = insn_fetch(int32_t, 4, _regs.eip); break;
+ case 1: src.val = insn_fetch(int8_t, 1); break;
+ case 2: src.val = insn_fetch(int16_t, 2); break;
+ case 4: src.val = insn_fetch(int32_t, 4); break;
}
break;
case SrcImmByte:
src.type = OP_IMM;
src.ptr = (unsigned long *)_regs.eip;
src.bytes = 1;
- src.val = insn_fetch(int8_t, 1, _regs.eip);
+ src.val = insn_fetch(int8_t, 1);
break;
}
if ( src.bytes == 8 ) src.bytes = 4;
switch ( src.bytes )
{
- case 1: src.val = insn_fetch(int8_t, 1, _regs.eip); break;
- case 2: src.val = insn_fetch(int16_t, 2, _regs.eip); break;
- case 4: src.val = insn_fetch(int32_t, 4, _regs.eip); break;
+ case 1: src.val = insn_fetch(int8_t, 1); break;
+ case 2: src.val = insn_fetch(int16_t, 2); break;
+ case 4: src.val = insn_fetch(int32_t, 4); break;
}
goto test;
case 2: /* not */